package com.yqw.onlineDocs.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yqw.onlineDocs.annotation.AuthCheck;
import com.yqw.onlineDocs.annotation.DocumentPermissionCheck;
import com.yqw.onlineDocs.common.BaseResponse;
import com.yqw.onlineDocs.common.DeleteRequest;
import com.yqw.onlineDocs.common.ErrorCode;
import com.yqw.onlineDocs.common.ResultUtils;
import com.yqw.onlineDocs.constant.DocumentPermissionConstant;
import com.yqw.onlineDocs.constant.UserConstant;
import com.yqw.onlineDocs.exception.BusinessException;
import com.yqw.onlineDocs.exception.ThrowUtils;
import com.yqw.onlineDocs.model.dto.document.DocumentAddRequest;
import com.yqw.onlineDocs.model.dto.document.DocumentAiGenerateRequest;
import com.yqw.onlineDocs.model.dto.document.DocumentEditRequest;
import com.yqw.onlineDocs.model.dto.document.DocumentQueryRequest;
import com.yqw.onlineDocs.model.dto.document.DocumentUpdateRequest;
import com.yqw.onlineDocs.model.entity.Document;
import com.yqw.onlineDocs.model.entity.DocumentUser;
import com.yqw.onlineDocs.model.entity.DocumentVersion;
import com.yqw.onlineDocs.model.entity.User;
import com.yqw.onlineDocs.model.enums.DocumentPermissionEnum;
import com.yqw.onlineDocs.model.enums.UserRoleEnum;
import com.yqw.onlineDocs.model.vo.DocumentVO;
import com.yqw.onlineDocs.service.DocumentService;
import com.yqw.onlineDocs.service.DocumentUserService;
import com.yqw.onlineDocs.service.DocumentVersionService;
import com.yqw.onlineDocs.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 文档接口
 */
@RestController
@RequestMapping("/document")
@Slf4j
public class DocumentController {

  @Resource
  private DocumentService documentService;

  @Resource
  private DocumentUserService documentUserService;

  @Resource
  private DocumentVersionService documentVersionService;

  @Resource
  private UserService userService;

  // region 增删改查

  /**
   * 创建文档
   *
   * @param documentAddRequest
   * @param request
   * @return
   */
  @PostMapping("/add")
  public BaseResponse<Long> addDocument(@RequestBody DocumentAddRequest documentAddRequest,
      HttpServletRequest request) {
    ThrowUtils.throwIf(documentAddRequest == null, ErrorCode.PARAMS_ERROR);
    // todo 在此处将实体类和 DTO 进行转换
    Document document = new Document();
    BeanUtils.copyProperties(documentAddRequest, document);
    // 数据校验
    documentService.validDocument(document, true);
    // todo 填充默认值
    User loginUser = userService.getLoginUser(request);
    document.setStatus(1);
    document.setUserId(loginUser.getId());
    // 写入数据库
    boolean result = documentService.save(document);
    ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    // 关联新增文档成员记录
    DocumentUser documentUser = new DocumentUser();
    documentUser.setDocumentId(document.getId());
    documentUser.setUserId(loginUser.getId());
    documentUser.setPermission(DocumentPermissionEnum.ADMIN.getValue());
    boolean res = documentUserService.save(documentUser);
    ThrowUtils.throwIf(!res, ErrorCode.OPERATION_ERROR, "创建文档成员记录失败");

    // 创建文档版本历史记录
    DocumentVersion documentVersion = new DocumentVersion();
    documentVersion.setDocumentId(document.getId());
    documentVersion.setVersion(1); // 初始版本号为1
    documentVersion.setContent(document.getContent());
    documentVersion.setUserId(loginUser.getId());
    documentVersion.setTitle(document.getTitle());
    documentVersion.setRemark("初始版本");
    boolean versionResult = documentVersionService.save(documentVersion);
    ThrowUtils.throwIf(!versionResult, ErrorCode.OPERATION_ERROR, "创建文档版本历史记录失败");

    // 返回新写入的数据 id
    long newDocumentId = document.getId();
    return ResultUtils.success(newDocumentId);
  }

  /**
   * 删除文档
   *
   * @param deleteRequest
   * @param request
   * @return
   */
  @PostMapping("/delete")
  @DocumentPermissionCheck(permission = DocumentPermissionConstant.DOCUMENT_WRITE, documentIdParam = "id", fromRequestBody = true)
  public BaseResponse<Boolean> deleteDocument(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
    if (deleteRequest == null || deleteRequest.getId() <= 0) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR);
    }
    User user = userService.getLoginUser(request);
    long id = deleteRequest.getId();
    // 判断是否存在
    Document oldDocument = documentService.getById(id);
    ThrowUtils.throwIf(oldDocument == null, ErrorCode.NOT_FOUND_ERROR);
    // // 仅本人或管理员可删除
    // if (!oldDocument.getUserId().equals(user.getId()) &&
    // !userService.isAdmin(request)) {
    // throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
    // }
    // 操作数据库
    boolean result = documentService.removeById(id);
    ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    return ResultUtils.success(true);
  }

  /**
   * 更新文档（仅管理员可用）
   *
   * @param documentUpdateRequest
   * @return
   */
  @PostMapping("/update")
  @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
  public BaseResponse<Boolean> updateDocument(@RequestBody DocumentUpdateRequest documentUpdateRequest) {
    if (documentUpdateRequest == null || documentUpdateRequest.getId() <= 0) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR);
    }
    // todo 在此处将实体类和 DTO 进行转换
    Document document = new Document();
    BeanUtils.copyProperties(documentUpdateRequest, document);
    // 数据校验
    documentService.validDocument(document, false);
    // 判断是否存在
    long id = documentUpdateRequest.getId();
    Document oldDocument = documentService.getById(id);
    ThrowUtils.throwIf(oldDocument == null, ErrorCode.NOT_FOUND_ERROR);
    // 操作数据库
    boolean result = documentService.updateById(document);
    ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    return ResultUtils.success(true);
  }

  /**
   * 根据 id 获取文档（封装类）
   *
   * @param id
   * @return
   */
  @GetMapping("/get/vo")
  @DocumentPermissionCheck(permission = DocumentPermissionConstant.DOCUMENT_READ, documentIdParam = "id", fromRequestBody = false)
  public BaseResponse<DocumentVO> getDocumentVOById(long id, HttpServletRequest request) {
    ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
    // 查询数据库
    Document document = documentService.getById(id);
    ThrowUtils.throwIf(document == null, ErrorCode.NOT_FOUND_ERROR);
    // 获取封装类
    return ResultUtils.success(documentService.getDocumentVO(document, request));
  }

  /**
   * 分页获取文档列表（仅管理员可用）
   *
   * @param documentQueryRequest
   * @return
   */
  @PostMapping("/list/page")
  @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
  public BaseResponse<Page<Document>> listDocumentByPage(@RequestBody DocumentQueryRequest documentQueryRequest) {
    long current = documentQueryRequest.getCurrent();
    long size = documentQueryRequest.getPageSize();
    // 查询数据库
    Page<Document> documentPage = documentService.page(new Page<>(current, size),
        documentService.getQueryWrapper(documentQueryRequest));
    return ResultUtils.success(documentPage);
  }

  /**
   * 分页获取文档列表（封装类）
   *
   * @param documentQueryRequest
   * @param request
   * @return
   */
  @PostMapping("/list/page/vo")
  @DocumentPermissionCheck(permission = DocumentPermissionConstant.DOCUMENT_READ, documentIdParam = "id")
  public BaseResponse<Page<DocumentVO>> listDocumentVOByPage(@RequestBody DocumentQueryRequest documentQueryRequest,
      HttpServletRequest request) {
    long current = documentQueryRequest.getCurrent();
    long size = documentQueryRequest.getPageSize();
    // 限制爬虫
    ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
    // 查询数据库
    Page<Document> documentPage = documentService.page(new Page<>(current, size),
        documentService.getQueryWrapper(documentQueryRequest));

    // 获取当前登录用户
    User loginUser = userService.getLoginUser(request);

    // 过滤掉用户没有权限的文档
    List<Document> filteredDocuments = documentPage.getRecords().stream().filter(document -> {
      // 如果是管理员，可以查看所有文档
      if (UserRoleEnum.ADMIN.getValue().equals(loginUser.getUserRole())) {
        return true;
      }

      // 如果是文档创建者，可以查看
      if (document.getUserId().equals(loginUser.getId())) {
        return true;
      }

      // 查询用户在该文档中的权限
      QueryWrapper<DocumentUser> queryWrapper = new QueryWrapper<>();
      queryWrapper.eq("documentId", document.getId());
      queryWrapper.eq("userId", loginUser.getId());
      DocumentUser documentUser = documentUserService.getOne(queryWrapper);

      // 用户不在文档成员列表中，无权查看
      return documentUser != null;
    }).collect(Collectors.toList());

    // 更新过滤后的记录
    documentPage.setRecords(filteredDocuments);

    // 获取封装类
    return ResultUtils.success(documentService.getDocumentVOPage(documentPage, request));
  }

  /**
   * 分页获取当前登录用户创建的文档列表
   *
   * @param documentQueryRequest
   * @param request
   * @return
   */
  @PostMapping("/my/list/page/vo")
  public BaseResponse<Page<DocumentVO>> listMyDocumentVOByPage(@RequestBody DocumentQueryRequest documentQueryRequest,
      HttpServletRequest request) {
    ThrowUtils.throwIf(documentQueryRequest == null, ErrorCode.PARAMS_ERROR);
    // 补充查询条件，只查询当前登录用户的数据
    User loginUser = userService.getLoginUser(request);
    documentQueryRequest.setUserId(loginUser.getId());
    long current = documentQueryRequest.getCurrent();
    long size = documentQueryRequest.getPageSize();
    // 限制爬虫
    ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
    // 查询数据库
    Page<Document> documentPage = documentService.page(new Page<>(current, size),
        documentService.getQueryWrapper(documentQueryRequest));
    // 获取封装类
    return ResultUtils.success(documentService.getDocumentVOPage(documentPage, request));
  }

  /**
   * 编辑文档（给用户使用）
   *
   * @param documentEditRequest
   * @param request
   * @return
   */
  @PostMapping("/edit")
  @DocumentPermissionCheck(permission = DocumentPermissionConstant.DOCUMENT_WRITE, documentIdParam = "id")
  public BaseResponse<Boolean> editDocument(@RequestBody DocumentEditRequest documentEditRequest,
      HttpServletRequest request) {
    if (documentEditRequest == null || documentEditRequest.getId() <= 0) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR);
    }
    // todo 在此处将实体类和 DTO 进行转换
    Document document = new Document();
    BeanUtils.copyProperties(documentEditRequest, document);
    // 数据校验
    documentService.validDocument(document, false);
    User loginUser = userService.getLoginUser(request);
    // 判断是否存在
    long id = documentEditRequest.getId();
    Document oldDocument = documentService.getById(id);
    ThrowUtils.throwIf(oldDocument == null, ErrorCode.NOT_FOUND_ERROR);
    // // 仅本人或管理员可编辑
    // if (!oldDocument.getUserId().equals(loginUser.getId()) &&
    // !userService.isAdmin(loginUser)) {
    // throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
    // }
    // 操作数据库
    boolean result = documentService.updateById(document);
    ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    return ResultUtils.success(true);
  }

  /**
   * 编辑文档并保存版本（给用户使用）
   *
   * @param documentEditRequest
   * @param request
   * @return
   */
  @PostMapping("/edit/saveVersion")
  @DocumentPermissionCheck(permission = DocumentPermissionConstant.DOCUMENT_WRITE, documentIdParam = "id")
  public BaseResponse<Boolean> editDocumentAndSaveVersion(@RequestBody DocumentEditRequest documentEditRequest,
      HttpServletRequest request) {
    if (documentEditRequest == null || documentEditRequest.getId() <= 0) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR);
    }
    // todo 在此处将实体类和 DTO 进行转换
    Document document = new Document();
    BeanUtils.copyProperties(documentEditRequest, document);
    // 数据校验
    documentService.validDocument(document, false);
    User loginUser = userService.getLoginUser(request);
    // 判断是否存在
    long id = documentEditRequest.getId();
    Document oldDocument = documentService.getById(id);
    ThrowUtils.throwIf(oldDocument == null, ErrorCode.NOT_FOUND_ERROR);
    boolean result = documentService.updateById(document);
    ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    // 获取该文档的最新版本号
    QueryWrapper<DocumentVersion> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("documentId", id);
    queryWrapper.orderByDesc("version");
    queryWrapper.last("LIMIT 1");
    DocumentVersion latestVersion = documentVersionService.getOne(queryWrapper);
    // 创建新的文档版本历史记录
    DocumentVersion documentVersion = new DocumentVersion();
    documentVersion.setDocumentId(id);
    // 如果存在版本记录，则版本号+1，否则设为1
    documentVersion.setVersion(latestVersion != null ? latestVersion.getVersion() + 1 : 1);
    documentVersion.setContent(document.getContent());
    documentVersion.setUserId(loginUser.getId());
    documentVersion.setTitle(document.getTitle());
    // 使用前端传递的备注，如果为空则使用默认值
    String remark = documentEditRequest.getRemark();
    documentVersion.setRemark(StringUtils.isBlank(remark) ? "编辑后版本" : remark);
    boolean versionResult = documentVersionService.save(documentVersion);
    ThrowUtils.throwIf(!versionResult, ErrorCode.OPERATION_ERROR, "创建文档版本历史记录失败");
    return ResultUtils.success(true);
  }

  // endregion

  /**
   * AI生成文档内容
   *
   * @param documentAiGenerateRequest
   * @param request
   * @return
   */
  @PostMapping("/ai/generate")
  public BaseResponse<String> generateDocumentByAi(@RequestBody DocumentAiGenerateRequest documentAiGenerateRequest,
      HttpServletRequest request) {
    // 校验请求参数
    ThrowUtils.throwIf(documentAiGenerateRequest == null, ErrorCode.PARAMS_ERROR);
    String prompt = documentAiGenerateRequest.getPrompt();
    ThrowUtils.throwIf(StringUtils.isBlank(prompt), ErrorCode.PARAMS_ERROR, "提示词不能为空");
    // 获取当前登录用户
    User loginUser = userService.getLoginUser(request);
    // 调用文档服务生成内容
    String generatedContent = documentService.generateDocumentContentByAi(prompt, loginUser);
    return ResultUtils.success(generatedContent);
  }
}
